package unimelb.discussiontracker.twitter.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import unimelb.discussiontracker.twitter.common.QueryControl;
import unimelb.discussiontracker.twitter.data.dao.IHashTagRankingDao;
import unimelb.discussiontracker.twitter.data.dao.ITopicDao;
import unimelb.discussiontracker.twitter.data.dao.ITopicIntervalAssociationDao;
import unimelb.discussiontracker.twitter.data.dao.ITweetRankingDao;
import unimelb.discussiontracker.twitter.data.dao.IUserRankingDao;
import unimelb.discussiontracker.twitter.data.entity.HashTagRanking;
import unimelb.discussiontracker.twitter.data.entity.TopicEntity;
import unimelb.discussiontracker.twitter.data.entity.TopicIntervalAssociation;
import unimelb.discussiontracker.twitter.data.entity.TweetRanking;
import unimelb.discussiontracker.twitter.data.entity.UserRanking;
import unimelb.discussiontracker.twitter.web.converter.IListConverter;
import unimelb.discussiontracker.twitter.web.model.HashTagItem;
import unimelb.discussiontracker.twitter.web.model.IntervalItem;
import unimelb.discussiontracker.twitter.web.model.PaginatedSearchResult;
import unimelb.discussiontracker.twitter.web.model.TopicItem;
import unimelb.discussiontracker.twitter.web.model.TweetItem;
import unimelb.discussiontracker.twitter.web.model.UserItem;

@Service
public class SearchService {

    @Autowired
    private ITopicDao topicDao;

    @Autowired
    private ITopicIntervalAssociationDao topicIntervalAssocDao;

    @Autowired
    private ITweetRankingDao tweetRankingDao;

    @Autowired
    private IUserRankingDao userRankingDao;

    @Autowired
    private IHashTagRankingDao tagRankingDao;

    @Autowired
    private IListConverter<TopicEntity, TopicItem> topicConverter;

    @Autowired
    private IListConverter<TopicIntervalAssociation, IntervalItem> intervalConverter;

    @Autowired
    private IListConverter<TweetRanking, TweetItem> tweetConverter;

    @Autowired
    private IListConverter<UserRanking, UserItem> userConverter;

    @Autowired
    private IListConverter<HashTagRanking, HashTagItem> tagConverter;

    @Transactional(readOnly = true)
    public List<TopicItem> searchAllTopics() {
        return topicConverter.convert(topicDao.findAll());
    }

    @Transactional(readOnly = true)
    public List<IntervalItem> searchIntervalsByTopicId(long topicId) {
        return intervalConverter.convert(topicIntervalAssocDao.findByTopicId(topicId));
    }

    @Transactional(readOnly = true)
    public IntervalItem searchTopicIntervalAssocByTopicIdAndIntervalid(long topicId, long intervalId) {
        final List<TopicIntervalAssociation> assocs = new ArrayList<TopicIntervalAssociation>();
        assocs.add(topicIntervalAssocDao.findByTopicIdAndIntervalId(topicId, intervalId));
        return intervalConverter.convert(assocs).get(0);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<TweetItem> searchKeywordBasedTweetRankings(long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = tweetRankingDao.countKeywordBasedRankings(topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<TweetItem> tweets = tweetConverter.convert(tweetRankingDao.findKeywordBasedRankings(topicId, intervalId, queryControl));

        return new PaginatedSearchResult<TweetItem>(tweets, totalResult, totalPageNumber, queryControl);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<TweetItem> searchUserBasedTweetRankings(long userId, long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = tweetRankingDao.countRankingsForUser(userId, topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<TweetItem> tweets = tweetConverter.convert(tweetRankingDao.findRankingsForUser(userId, topicId, intervalId, queryControl));

        return new PaginatedSearchResult<TweetItem>(tweets, totalResult, totalPageNumber, queryControl);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<TweetItem> searchTagBasedTweetRankings(long tagId, long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = tweetRankingDao.countRankingsForTag(tagId, topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<TweetItem> tweets = tweetConverter.convert(tweetRankingDao.findRankingsForTag(tagId, topicId, intervalId, queryControl));

        return new PaginatedSearchResult<TweetItem>(tweets, totalResult, totalPageNumber, queryControl);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<UserItem> searchKeywordBasedUserRankings(long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = userRankingDao.countKeywordBasedRankings(topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<UserItem> users = userConverter.convert(userRankingDao.findKeywordBasedRankings(topicId, intervalId, queryControl));

        return new PaginatedSearchResult<UserItem>(users, totalResult, totalPageNumber, queryControl);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<UserItem> searchTagBasedUserRankings(long tagId, long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = userRankingDao.countRankingsByTag(tagId, topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<UserItem> users = userConverter.convert(userRankingDao.findRankingsByTag(tagId, topicId, intervalId, queryControl));

        return new PaginatedSearchResult<UserItem>(users, totalResult, totalPageNumber, queryControl);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<HashTagItem> searchKeywordBasedTagRankings(long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = tagRankingDao.countKeywordBasedRankings(topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<HashTagItem> tags = tagConverter.convert(tagRankingDao.findKeywordBasedRankings(topicId, intervalId, queryControl));

        return new PaginatedSearchResult<HashTagItem>(tags, totalResult, totalPageNumber, queryControl);
    }

    @Transactional(readOnly = true)
    public PaginatedSearchResult<HashTagItem> searchUserBasedTagRankings(long userId, long topicId, long intervalId, QueryControl queryControl) {
        final long totalResult = tagRankingDao.countRankingsByUser(userId, topicId, intervalId);

        final long totalPageNumber = calculateTotalPageNumber(queryControl.getPageSize(), totalResult);

        final List<HashTagItem> tags = tagConverter.convert(tagRankingDao.findRankingsByUser(userId, topicId, intervalId, queryControl));

        return new PaginatedSearchResult<HashTagItem>(tags, totalResult, totalPageNumber, queryControl);
    }

    private long calculateTotalPageNumber(int pageSize, final long totalResult) {
        long totalPageNumber = -1;
        if (totalResult <= pageSize) {
            totalPageNumber = 1;
        } else {
            totalPageNumber = ((totalResult % pageSize) > 0) ? totalResult / pageSize + 1 : totalResult / pageSize;
        }
        return totalPageNumber;
    }
}
